/*--------------------------------------------------------------------------------------*\
**
** kingdom_overview_window.cpp
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "kingdom_overview_window.h"

#include <vector>
#include "abbreviate_number.h"
#include "adventure_frame.h"
#include "adaptor_handler.h"
#include "adv_object_list_image.h"
#include "adventure_map.h"
#include "adventure_map_window.h"
#include "army.h"
#include "army_array.h"
#include "army_array_ptr.h"
#include "army_list_window.h"
#include "artifact_keyword.h"
#include "artifact_type.h"
#include "artifact_properties.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_group_ptr.h"
#include "bitmap_group_window.h"
#include "bitmap_layer_cache.h"
#include "bitmap_layer_cache_window.h"
#include "building_traits.h"
#include "button.h"
#include "button_cache.h"
#include "caravan.h"
#include "caravan_set.h"
#include "cached_grail_data_source.h"
#include "convert_16_bit.h"
#include "creature.h"
#include "creature_array_window.h"
#include "creature_stack.h"
#include "creature_traits.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "get_artifact_damage_modifier.h"
#include "hero.h"
#include "interface_help.h"
#include "item_help_block.h"
#include "luck_icon_window.h"
#include "material_icons.h"
#include "micro_map_window.h"
#include "mini_map_window.h"
#include "morale_icon_window.h"
#include "options.h"
#include "ownable_garrisonable_adv_object.h"
#include "ownable_garrisonable_adv_object_list.h"
#include "ownable_garrisonable_adv_object_ptr.h"
#include "player.h"
#include "replace_keywords.h"
#include "scrollbar.h"
#include "simple_dialog.h"
#include "skill.h"
#include "skill_icon.h"
#include "skill_properties.h"
#include "spellbook_window.h"
#include "standard_fonts.h"
#include "terrain.h"
#include "toggle_button.h"
#include "town.h"
#include "town_list.h"
#include "town_window.h"
#include "town_properties.h"

extern  t_button_cache			    g_ok_button;
extern  t_bitmap_group_cache        g_creature_rings;
extern  t_bitmap_group_cache        g_town_list_bitmaps;
extern	t_bitmap_layer_cache		g_town_marker;
extern  t_external_string const k_text_day( "day.text" );

t_button* create_blacksmith_button( std::string const& name, t_bitmap_group_ptr bitmap_ptr, t_window *parent_window );

namespace 
{ // unnamed namespace

    t_bitmap_group_cache     k_kingdom_overview_layout_bitmaps ("dialog.kingdom_overview.layout");
    t_bitmap_group_cache     k_kingdom_overview_army_list_bitmaps ("dialog.kingdom_overview.army_list");
    t_bitmap_group_cache     k_kingdom_overview_hero_list_bitmaps ("dialog.kingdom_overview.hero_list");
    t_bitmap_group_cache     k_kingdom_overview_town_list_bitmaps ("dialog.kingdom_overview.town_list");

    t_external_string const k_text_overview_title( "kingdom_overview_title.misc" );
    t_external_string const k_text_army_list_button( "kingdom_overview_army_list.misc" );
    t_external_string const k_text_hero_list_button( "kingdom_overview_hero_list.misc" );
    t_external_string const k_text_town_list_button( "kingdom_overview_town_list.misc" );

    t_external_string const k_text_garrison_text ( "kingdom_overview_garrison.misc" );
    t_external_string const k_text_hire_text ( "kingdom_overview_hire.misc" );
    t_external_string const k_town_gold_help_text ( "kingdom_overview_gold.misc" );

    // Copied from army_list_window...
	struct t_sort_skills
	{
		bool operator()( t_skill const& left, t_skill const& right ) const
		{
			bool left_is_primary = left.skill < k_skill_primary_count;
			bool right_is_primary = right.skill < k_skill_primary_count;

			if (left_is_primary != right_is_primary)
				return left_is_primary;
			if (left.level != right.level)
				return left.level > right.level;
			return left.skill < right.skill;
		}
	};

    const   int k_number_of_creature_portraits = 6;
    class t_town_creature_window : public t_window
    {
        public:
            t_town_creature_window( t_screen_point const& origin, 
		                                          std::vector<t_creature_type> creature_type_list,
												  t_window* parent );
        protected:
    };

}; // end unnamed namespace

/*----------------------------------------------------------------------------*\
**
** Rings for displaying town creatures.
**
\*----------------------------------------------------------------------------*/
t_town_creature_window::t_town_creature_window( t_screen_point const& origin, std::vector<t_creature_type> creature_type_list,
												  t_window* parent )
					   : t_window( t_screen_rect(origin.x, origin.y, origin.x, origin.y),
					               k_completely_transparent, parent )
{
	t_bitmap_group_ptr bitmap_rings = g_creature_rings.get();

	// create portraits / buttons
	int            i;
	t_screen_point point;
	t_screen_point portrait_point;

    // Don't need top & bottom for this one...
	static char const* k_names[3][3] = 
	{
		{ "top_left",		"top",		"top_right" },
		{ "left",			"middle",	"right" },
		{ "bottom_left",	"bottom",	"bottom_right" }
	};

	static int const k_layout[k_number_of_creature_portraits][2] =
	{
		{ 1, 0 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 2 }
	};

	t_bitmap_layer const* layer[3][3];
	t_bitmap_layer const* highlight[3][3];
	int                   row;
	int                   column;
	std::string           layer_name;

	// Load layers from border file.
	for (row = 0; row < 3; row++)
	{
		for (column = 0; column < 3; column++)
		{
			layer_name = k_names[row][column];
			layer[row][column] = bitmap_rings->find( layer_name );
			layer_name += "_highlight" ;
			highlight[row][column] = bitmap_rings->find( layer_name );
		}
	}

	// find the offset of the portrait relative to the border
	t_screen_rect           portrait_rect = bitmap_rings->find( "portrait" )->get_rect();
	t_screen_point          portrait_offset = portrait_rect.top_left();
	t_screen_point          border_offset;
	t_bitmap_layer const*   border;

    // Portrait frames.
	t_bitmap_layer_window * portrait_window;
	t_bitmap_layer_window * portrait_border;

	point.x = 0;
	point.y = 0;

    // NOTE: Begin a width of a half portrait in.
	border = layer[1][0];
	point.x += (border->get_width()/2);

	for (i = 0; i < k_number_of_creature_portraits; i++)
	{
		row = k_layout[i][0];
		column = k_layout[i][1];

		// get the appropriate border
		border = layer[row][column];
		// make upper left corner of border == point
		border_offset = -border->get_rect().top_left();

        portrait_point = point + portrait_rect.top_left() + border_offset;

		portrait_window = new t_bitmap_layer_window( t_bitmap_layer_ptr(),
			                        portrait_point, this );

        if (i<creature_type_list.size())
        {
			portrait_window->set_bitmap( get_creature_portrait( creature_type_list[i], 52 ) );
		    portrait_window->set_help_balloon_text( get_creature_name(  creature_type_list[i], -1, false ) );
        }
        
		// create border
		portrait_border = new t_bitmap_layer_window( border, point + border_offset, this );

		point.x += border->get_width();
	}

	set_size_from_children();
}

/*--------------------------------------------------------------------------------*\
**
** Constructer for hero location mini-map.
**
\*--------------------------------------------------------------------------------*/
t_center_map_window::t_center_map_window( t_adventure_map const& map, t_screen_rect const& rect, 
		                              t_adventure_map_window* map_window, t_window* parent )
				 : t_window( k_no_transparency, parent), t_mini_map_renderer( map, map_window->get_frame()->get_team_view() ),
				   m_map_window( map_window )
{
	init( rect );
	resize( rect.size() );
	m_dragging = false;
}

/*
** Hero mini-map.
*/
void t_center_map_window::paint( t_paint_surface& paint_surface )
{
	update( paint_surface.get_rect() );
	paint_surface.draw( t_screen_point(0,0), *m_back_buffer, m_back_buffer->get_rect() );
}

/*
** Hero mini-map.
*/
t_shared_ptr< t_abstract_bitmap16 > t_center_map_window::create_back_buffer( t_screen_point const & size )
{
	m_back_buffer = new t_memory_bitmap16( size.x, size.y );
	return m_back_buffer;
}

void t_center_map_window::on_rect_dirtied( t_screen_rect const & rect )
{
	invalidate( rect );
}

/*
** Resize hero mini-map.
*/
void t_center_map_window::on_size_change( t_screen_rect const& rect )
{
	resize( rect.size() );
}

void t_center_map_window::on_view_level_changed( int level )
{
}

void t_center_map_window::on_view_resized( t_screen_point const & size )
{
}

void t_center_map_window::center_view( t_screen_point point )
{
	if (!m_dragging)
		return;
	t_screen_point map_size = get_adventure_map().get_view_size();
	t_screen_point mini_map_size = get_view_size();

	point.x = point.x * map_size.x / mini_map_size.x;
	point.y = point.y * map_size.y / mini_map_size.y;

	m_map_window->center_view( point );
}


/*--------------------------------------------------------------------------------------------------------*\
**
** Kingdom overview constructor.
**
\*--------------------------------------------------------------------------------------------------------*/
t_kingdom_overview_window::t_kingdom_overview_window( t_window* parent, t_adventure_frame * frame_ptr, t_player * player_ptr )
                   : t_window( k_completely_transparent, parent )
{
	t_screen_rect rect;
    int i;

    m_player_ptr = player_ptr;
    m_adventure_frame_ptr = frame_ptr;
    m_adventure_map_window_ptr = frame_ptr->get_map_window();

	/*
    ** Load bitmaps, set window position.
    */
	t_screen_rect parent_rect;

	m_background_bitmaps_ptr = k_kingdom_overview_layout_bitmaps.get();
	parent_rect = get_parent()->get_client_rect();
	rect = m_background_bitmaps_ptr->get_rect();
	rect += (parent_rect.size() - rect.size()) / 2;
	init( rect );

	/*
    ** Create background bitmap.
    */
	t_bitmap_layer const*   layer;
	t_window*               window;
	t_window*               background;
	t_screen_point          origin(0,0);

	layer = m_background_bitmaps_ptr->find( "background" );
	background = new t_bitmap_layer_window( layer, origin, this );

    /*
    ** Text.
    */
	t_text_window*          text_window_ptr;

	rect = m_background_bitmaps_ptr->find( "title" )->get_rect(); // + origin;
	text_window_ptr  = new t_text_window( get_font( rect.height() ), rect, this, "", t_pixel_24(0,0,0) );
    text_window_ptr->set_text ( k_text_overview_title );
	text_window_ptr->set_center_horizontal();

    // Materials.
	t_adventure_map const&  adventure_map = *frame_ptr->get_map();
	int						day = adventure_map.get_day();
	std::string     material_amount_text;
	t_material_array const& funds = player_ptr->get_funds();
	t_material_array const& income = player_ptr->get_income( day );
	t_help_block const&   material_help = get_help_block( "material_display" );

	for (i = 0; i < k_material_count; i++)
	{
        std::string     material_help_text;

	    layer = m_background_bitmaps_ptr->find( k_material_keyword[i] );
	    window = new t_bitmap_layer_window( layer, origin, this );

        // Set help.
        window->set_help_balloon_text( k_material_keyword[i] );
		set_help( window, material_help, k_material_keyword[i] );
        
        player_ptr->get_income_text( day, i, material_help_text );
        window->set_right_click_text( material_help_text );

        // Text show kingdom material amount.
		material_amount_text = format_string ( "%s_owned", k_material_keyword[i] );
    	rect = m_background_bitmaps_ptr->find( material_amount_text )->get_rect();
		text_window_ptr = new t_text_window( get_font( rect.height() ), rect, this, "", t_pixel_24(0,0,0) );
        text_window_ptr->set_text( abbreviate_number( funds[i], *text_window_ptr->get_font(),
									text_window_ptr->get_width()));
		text_window_ptr->set_center_horizontal();

        // Income for material.
	    std::string     income_text;

		material_amount_text = format_string ( "%s_earned", k_material_keyword[i] );
    	rect = m_background_bitmaps_ptr->find( material_amount_text )->get_rect();
		text_window_ptr = new t_text_window( get_font( rect.height() ), rect, this, "", t_pixel_24(0,0,0) );

        // Show daily income text.
        income_text = format_string( "%s/%s", abbreviate_number( income[i], *text_window_ptr->get_font(), text_window_ptr->get_width()).c_str(),
                        k_text_day.c_str() );

        text_window_ptr->set_text( income_text ); //abbreviate_number( income[i], *text_window_ptr->get_font(), text_window_ptr->get_width()));
		text_window_ptr->set_center_horizontal();
    }

    /*
    ** Create buttons.
    */
	t_button            *button_ptr;
	t_help_block const&		help = get_help_block( "kingdom_overview" );

    button_ptr = create_blacksmith_button( "army_list", m_background_bitmaps_ptr, this );
	button_ptr->set_click_handler( bound_handler( *this, &t_kingdom_overview_window::army_list_click ));
	set_help( button_ptr, help, "army_list" );

    button_ptr = create_blacksmith_button( "hero_list", m_background_bitmaps_ptr, this );
	button_ptr->set_click_handler( bound_handler( *this, &t_kingdom_overview_window::hero_list_click ));
	set_help( button_ptr, help, "hero_list" );

    button_ptr = create_blacksmith_button( "town_list", m_background_bitmaps_ptr, this );
	button_ptr->set_click_handler( bound_handler( *this, &t_kingdom_overview_window::town_list_click ));
	set_help( button_ptr, help, "town_list" );

	// Create close button
	rect = m_background_bitmaps_ptr->find( "close_button" )->get_rect();
	button_ptr = new t_button( g_ok_button.get(), rect.top_left(), this );
	button_ptr->set_click_handler( bound_handler( *this, &t_kingdom_overview_window::close_click ));
	set_help( button_ptr, help, "close" );

	rect = m_background_bitmaps_ptr->find( "scrollbar" )->get_rect();
	m_scrollbar = new t_scrollbar( rect.top_left(), rect.height(), this, 0, 0, true );
	m_scrollbar->set_position( 0 );
	m_scrollbar->set_limits( 0, 0 );

    create_army_list_screen();
    create_hero_list_screen();
    create_town_list_screen();

    // Set hero list window (default).
    town_list_click( NULL );
}

/*--------------------------------------------------------------------------------------------------*\
**
** Army list screen.
**
\*--------------------------------------------------------------------------------------------------*/
void t_kingdom_overview_window::create_army_list_screen()
{
    int                 i;
	t_screen_rect       rect = m_background_bitmaps_ptr->find( "views" )->get_rect();
    
    m_army_list_bitmaps_ptr = k_kingdom_overview_army_list_bitmaps.get();
    
    // Window holder.
	m_army_list_window = new t_window ( rect, k_completely_transparent, this );
	m_army_list_window->set_visible( false );
    m_army_list_starting_index = 0;

    /*
    ** Get hero list.
    */
	t_army_array *  army_list = m_player_ptr->get_armies();
	t_screen_point  point(0, 0);

    // Create all the army windows.  Then set visible as necessary.
    for (i=0; i<army_list->size(); i++)
    {
	    t_army* army_ptr = (*army_list)[i];
	    
        create_army_frame( army_ptr, i );
    }
	t_bitmap_layer const*   layer;
    layer = m_army_list_bitmaps_ptr->find( "army_frame_highlight" );
    m_army_leader_highlight = new t_bitmap_layer_window( layer, t_screen_point(0,0), m_army_list_window );
}

// Create individual army frame.
void t_kingdom_overview_window::create_army_frame( t_army * army_ptr, int index )
{
	t_window*           window_ptr;
	t_bitmap_layer const*   layer;
	t_screen_point      origin( 0, 0 );
    t_creature_array&   creatures = army_ptr->get_creatures();
	t_creature_stack const& leader = creatures.get_leader();
	t_screen_rect       portrait_rect = m_army_list_bitmaps_ptr->find( "portrait" )->get_rect();
	t_button_handler	handler;

    // Base all frames off the first frame...
    t_screen_rect   rect = m_army_list_bitmaps_ptr->find( "army_1" )->get_rect();
	t_window*       army_window_ptr;

    // Create army info window.
    army_window_ptr = new t_window ( rect, k_completely_transparent, m_army_list_window );
    m_army_windows.push_back( army_window_ptr );

    /*
    ** Create army leader frame.  Allow button click to go to location in map.
    */
    t_creature_array_window* creature_window_ptr;

    create_army_leader_frame( army_window_ptr, army_ptr );

    // Put this after because skills need to be under this layer.
    layer = m_army_list_bitmaps_ptr->find( "army_leader" );
    window_ptr = new t_bitmap_layer_window( layer, origin, army_window_ptr );

    // Create button from portrait.
	t_button            *button_ptr;
	button_ptr = new t_button( portrait_rect.top_left(), army_window_ptr );

    layer = leader.get_portrait();
    window_ptr = new t_bitmap_layer_window( layer, origin, button_ptr );
	window_ptr->set_help_balloon_text( leader.get_name() );

    button_ptr->set_released_image( window_ptr );
    handler = add_2nd_argument( add_2nd_argument( bound_handler( *this, &t_kingdom_overview_window::army_leader_clicked ), army_ptr ),
                                    index );
    button_ptr->set_click_handler( handler );
	button_ptr->set_double_click_handler( add_2nd_argument( bound_handler( *this, 
                                    &t_kingdom_overview_window::army_leader_double_clicked ), army_ptr ));

    button_ptr->enable( true );
    button_ptr->update_size();

    layer = m_army_list_bitmaps_ptr->find( "frame" );
    window_ptr = new t_bitmap_layer_window( layer, origin, army_window_ptr );

    layer = m_army_list_bitmaps_ptr->find( "ring_background" );
    window_ptr = new t_bitmap_layer_window( layer, origin, army_window_ptr );

    // Show army.  Use 6 portraits instead of 7 (no leader)?
    rect = m_army_list_bitmaps_ptr->find( "garrison_rings" )->get_rect();
	creature_window_ptr = new t_creature_array_window( rect.top_left(), &creatures, t_creature_array_window::k_single_row, 
                    0, army_window_ptr, false );

    /*
    ** Mini-map.  Allow button click to go to location in map.
    */
	t_center_map_window *   mini_map_ptr;
	t_bitmap_layer *      hero_marker = m_army_list_bitmaps_ptr->find( "marker" );
	rect = hero_marker->get_rect();
	hero_marker->offset( -rect.top_left() );

    t_adventure_map *           map_ptr = m_adventure_frame_ptr->get_map();
    t_level_map_point_2d        army_point = army_ptr->get_position();

    rect = m_army_list_bitmaps_ptr->find( "map" )->get_rect();
	button_ptr = new t_button( rect.top_left(), army_window_ptr );

    rect -= rect.top_left();
  	mini_map_ptr = new t_center_map_window( *map_ptr, rect, m_adventure_map_window_ptr, button_ptr );
  	//mini_map_ptr = new t_center_map_window( *map_ptr, rect, m_adventure_map_window_ptr, army_window_ptr );
    mini_map_ptr->set_view_level ( army_point.level );
    
    button_ptr->set_released_image( mini_map_ptr );
    button_ptr->set_click_handler( handler );
    button_ptr->enable( true );
    button_ptr->update_size();

    // Show hero marker position.
    origin = mini_map_ptr->get_tile_rect( army_point ).top_left();
    window_ptr = new t_bitmap_layer_window( hero_marker, origin, mini_map_ptr );
}

// Move bar. - (from army_list_window)
static void set_bar_height( int value, int max_value, t_window* bar,
						   t_window* clipper, t_window* background )
{
	int maximum			= bar->get_height();
	int height			= value * maximum / max_value;
	t_screen_rect rect	= clipper->get_screen_rect();

	if (height > maximum)
		height = maximum;
	rect.top = rect.bottom - height;
	clipper->move_screen_rect( rect, false );
}

// Show move, mana, etc. for army leader.
void t_kingdom_overview_window::create_army_leader_frame( t_window* parent_ptr, t_army * army_ptr )
{
    t_creature_array&   creatures = army_ptr->get_creatures();
	t_creature_stack const& leader = creatures.get_leader();
    const t_hero *          hero_ptr = leader.get_hero();
	t_screen_rect           skill_rect;
	t_screen_point          origin( 0, 0 );
	t_window*               window_ptr;

#if (0)
    if (hero_ptr)
    {
        int                     i;
        // Show top 2 skills.
    	std::vector<t_skill> skills = hero_ptr->get_skills();
    	std::sort( skills.begin(), skills.end(), t_sort_skills() );

    	for (i = 0; i < 2 && i < skills.size(); i++)
    	{
            skill_rect = m_army_list_bitmaps_ptr->find( format_string ("skill_%d", (i+1)) )->get_rect();
            t_skill_icon_ptr    skill_icon_ptr = new t_skill_icon( skills[i], skill_rect, parent_ptr );
            skill_icon_ptr->set_visible( true );
        }
	}
#endif

    // Move bar. - (from army_list_window)
	t_window*               clipper_ptr;
	t_window*               background_ptr;
    t_screen_rect           rect;
    int                     value;

	value = army_ptr->get_movement();
	if (value < army_ptr->get_next_step_cost())
		value = 0;

	t_bitmap_layer const* move_bar = m_army_list_bitmaps_ptr->find( "move_bar" );
	rect = move_bar->get_rect();
	background_ptr = new t_window( rect, k_some_transparency, parent_ptr );
	clipper_ptr = new t_window( rect - rect.top_left(), k_completely_transparent,
		                                  background_ptr );
    window_ptr = new t_bitmap_layer_window( move_bar, origin, clipper_ptr, false );
	set_bar_height( value, 1500, window_ptr, clipper_ptr,
		            background_ptr );

    // Mana(strength) bar.
    value = army_ptr->get_creatures().get_experience_value();
	value = (log( (double)value ) - log( (double)t_army_list_window::k_minimum_army_value )) * t_army_list_window::k_log_multiplier;
	int maximum = (log( (double)t_army_list_window::k_maximum_army_value ) - 
                    log( (double)t_army_list_window::k_minimum_army_value)) * t_army_list_window::k_log_multiplier;

	t_bitmap_layer const* mana_bar = m_army_list_bitmaps_ptr->find( "mana_bar" );
	rect = mana_bar->get_rect();
	background_ptr = new t_window( rect, k_some_transparency, parent_ptr );
	clipper_ptr = new t_window( rect - rect.top_left(), k_completely_transparent,
		                                  background_ptr );

    window_ptr = new t_bitmap_layer_window( mana_bar, origin, clipper_ptr, false );
	set_bar_height( value, maximum, window_ptr, clipper_ptr,
		            background_ptr );
}

void t_kingdom_overview_window::show_army_list_screen( int starting_index )
{
    int i;
    int window_index;
	t_screen_point      point(0, 0);

    if (starting_index > m_army_windows.size())
        return;

	m_army_list_window->set_visible( true );
	m_army_list_starting_index = starting_index;

    // Show armies in selected range.
	std::string             army_frame_name;
    i = 0;

    for (window_index = 0; window_index<m_army_windows.size(); window_index++)
    {
        if ((window_index >= starting_index) && (i < k_max_army_list_windows))
        {
    		army_frame_name = format_string ( "army_%d", (i+1) );

    	    point = m_army_list_bitmaps_ptr->find( army_frame_name )->get_rect().top_left();

            m_army_windows[ window_index ]->move ( point );
            m_army_windows[ window_index ]->set_visible( true );

            i++;
        }
        // Set rest to be not visible.
        else
        {
            m_army_windows[ window_index ]->set_visible( false );
        }
    }

    int scrollbar_limit = 0;
    if ( m_army_windows.size() > k_max_army_list_windows )
    {
        scrollbar_limit = m_army_windows.size() - k_max_army_list_windows;

	    m_scrollbar->set_handler( bound_handler( *this, &t_kingdom_overview_window::army_list_scrollbar_move));
    	m_scrollbar->set_limits( 0, scrollbar_limit );
    	m_scrollbar->set_visible( true );
    }
    else
    	m_scrollbar->set_visible( false );
}

void t_kingdom_overview_window::hide_army_list_screen()
{
	m_army_list_window->set_visible( false );
}

void t_kingdom_overview_window::army_list_scrollbar_move( t_scrollbar* scrollbar, int value )
{
    show_army_list_screen( value );
}

/*--------------------------------------------------------------------------------------------------*\
**
** Hero list screen.
**
\*--------------------------------------------------------------------------------------------------*/
void t_kingdom_overview_window::create_hero_list_screen()
{
    int             i;
    int             j;
    t_hero  *       hero_ptr;
	t_window*       window_ptr;
	t_screen_rect   rect = m_background_bitmaps_ptr->find( "views" )->get_rect();
	t_screen_point  origin( 0, 0 ); // = m_background_bitmaps_ptr->find( "views" )->get_rect().top_left();
	t_help_block const&     army_help_block = get_help_block( "army_screen" );
	t_help_block const&     shared_help_block = get_help_block( "shared" );

    m_hero_list_bitmaps_ptr = k_kingdom_overview_hero_list_bitmaps.get();

    // Window holder.
	m_hero_list_window = new t_window ( rect, k_completely_transparent, this );
	m_hero_list_window->set_visible( false );

	/*
    ** Create bitmaps.
    */
	t_bitmap_layer const*   layer;

	layer = m_hero_list_bitmaps_ptr->find( "background" );
	m_hero_background_ptr = new t_bitmap_layer_window( layer, origin, m_hero_list_window );

    create_skill_frames();

    // After skill icons, to be above them.
    layer = m_hero_list_bitmaps_ptr->find( "skill_frame" );
	window_ptr = new t_bitmap_layer_window( layer, origin, m_hero_list_window );

	layer = m_hero_list_bitmaps_ptr->find( "melee" );
	window_ptr = new t_bitmap_layer_window( layer, origin, m_hero_list_window );
   	set_help( window_ptr, shared_help_block, "damage" );
	rect = m_hero_list_bitmaps_ptr->find( "damage_text" )->get_rect();
	m_damage_text = new t_text_window( get_font( rect.height() ), rect, m_hero_list_window, "", t_pixel_24(0,0,0) );
	m_damage_text->set_center_horizontal();

	layer = m_hero_list_bitmaps_ptr->find( "hit_points" );
	window_ptr = new t_bitmap_layer_window( layer, origin, m_hero_list_window );
   	set_help( window_ptr, shared_help_block, "hit_points" );
	rect = m_hero_list_bitmaps_ptr->find( "health_text" )->get_rect();
	m_health_text = new t_text_window( get_font( rect.height() ), rect, m_hero_list_window, "", t_pixel_24(0,0,0) );
	m_health_text->set_center_horizontal();

	layer = m_hero_list_bitmaps_ptr->find( "spell_points" );
	window_ptr = new t_bitmap_layer_window( layer, origin, m_hero_list_window );
   	set_help( window_ptr, shared_help_block, "spell_points" );
	rect = m_hero_list_bitmaps_ptr->find( "spell_points_text" )->get_rect();
	m_spell_points_text = new t_text_window( get_font( rect.height() ), rect, m_hero_list_window, "", t_pixel_24(0,0,0) );
	m_spell_points_text->set_center_horizontal();

	layer = m_hero_list_bitmaps_ptr->find( "experience" );
	m_experience_icon = new t_bitmap_layer_window( layer, origin, m_hero_list_window );
   	set_help( m_experience_icon, shared_help_block, "experience" );
	rect = m_hero_list_bitmaps_ptr->find( "experience_text" )->get_rect();
	m_experience_text = new t_text_window( get_font( rect.height() ), rect, m_hero_list_window, "", t_pixel_24(0,0,0) );
	m_experience_text->set_center_horizontal();

	layer = m_hero_list_bitmaps_ptr->find( "speed" );
	window_ptr = new t_bitmap_layer_window( layer, origin, m_hero_list_window );
   	set_help( window_ptr, shared_help_block, "speed" );
	rect = m_hero_list_bitmaps_ptr->find( "speed_text" )->get_rect();
	m_speed_text = new t_text_window( get_font( rect.height() ), rect, m_hero_list_window, "", t_pixel_24(0,0,0) );
	m_speed_text->set_center_horizontal();

	layer = m_hero_list_bitmaps_ptr->find( "move" );
	window_ptr = new t_bitmap_layer_window( layer, origin, m_hero_list_window );
   	set_help( window_ptr, shared_help_block, "movement" );
	rect = m_hero_list_bitmaps_ptr->find( "movement_text" )->get_rect();
	m_movement_text = new t_text_window( get_font( rect.height() ), rect, m_hero_list_window, "", t_pixel_24(0,0,0) );
	m_movement_text->set_center_horizontal();

    // Luck
	rect = m_hero_list_bitmaps_ptr->find( "luck" )->get_rect();
	m_luck_icon_ptr = new t_luck_icon_window( rect, m_hero_list_window );
   	//set_help( luck_icon_ptr, shared_help_block, "luck" );
    
    rect = m_hero_list_bitmaps_ptr->find( "luck_text" )->get_rect();
	m_luck_text = new t_text_window( get_font( rect.height() ), rect, m_hero_list_window, "", t_pixel_24(0,0,0) );
	m_luck_text->set_center_horizontal();

    // Morale
	rect = m_hero_list_bitmaps_ptr->find( "morale" )->get_rect();
	m_morale_icon_ptr = new t_morale_icon_window( rect, m_hero_list_window );
   	//set_help( creature_morale_icon_ptr, shared_help_block, "morale" );

    rect = m_hero_list_bitmaps_ptr->find( "morale_text" )->get_rect();
	m_morale_text = new t_text_window( get_font( rect.height() ), rect, m_hero_list_window, "", t_pixel_24(0,0,0) );
	m_morale_text->set_center_horizontal();

    // Bio button.
	t_button            *button_ptr;
    button_ptr = create_blacksmith_button( "bio", m_hero_list_bitmaps_ptr, m_hero_list_window );
	button_ptr->set_click_handler( bound_handler( *this, &t_kingdom_overview_window::hero_bio_clicked ));
	set_help( button_ptr, army_help_block, "biography" );

    // Spellbook button.
    button_ptr = create_blacksmith_button( "spellbook", m_hero_list_bitmaps_ptr, m_hero_list_window );
	button_ptr->set_click_handler( bound_handler( *this, &t_kingdom_overview_window::hero_spellbook_clicked ));
	set_help( button_ptr, army_help_block, "spellbook" );

    /*
    ** Get army list.
    */
	t_army_array *  army_list = m_player_ptr->get_armies();
	t_screen_point  point(0, 0);

    // Create all the hero windows.  Then set visible as necessary.
    int hero_count = 0;

    // Go through armies.
    for (i=0; i<army_list->size(); i++)
    {
	    t_army* army_ptr = (*army_list)[i];
	    t_creature_array&    creatures = army_ptr->get_creatures();
	    
        for (j = 0; j < t_creature_array::k_size; j++)
    	{
	    	hero_ptr = creatures[j].get_hero();
            if (hero_ptr == 0)
			    continue;

            // Order of heroes/army must match.
            m_heroes_list.push_back( hero_ptr );
	        m_heroes_creatures_list.push_back( army_ptr );

	        t_level_map_point_2d map_point = army_ptr->get_position();
            create_hero_frame( hero_ptr, map_point, hero_count );
	        hero_count++;
        }
    }
    // Go through towns.
	t_town_list& town_list = *m_player_ptr->get_towns();
	t_town_list::const_iterator town_iter;
	for (town_iter = town_list.begin(); town_iter != town_list.end(); town_iter++)
    {
	    t_creature_array&    creatures = (*town_iter)->get_garrison();
        for (j = 0; j < t_creature_array::k_size; j++)
    	{
	    	hero_ptr = creatures[j].get_hero();
            if (hero_ptr == 0)
			    continue;

            // Order of heroes/creatures must match.
            m_heroes_list.push_back( hero_ptr );
	        m_heroes_creatures_list.push_back( &creatures );

	        t_level_map_point_2d map_point = (*town_iter)->get_position();
            create_hero_frame( hero_ptr, map_point, hero_count );
	        hero_count++;
        }
    }

    /*
    ** Get heroes from garrison list.
    */
	t_ownable_garrisonable_adv_object_list const & garrison_list = m_player_ptr->get_garrisons();
    t_ownable_garrisonable_adv_object_list::const_iterator garrison_iter;
	for (garrison_iter = garrison_list.begin(); garrison_iter != garrison_list.end(); garrison_iter++)
    {
	    t_creature_array&    creatures = (*garrison_iter)->get_garrison();
        for (j = 0; j < t_creature_array::k_size; j++)
    	{
	    	hero_ptr = creatures[j].get_hero();
            if (hero_ptr == 0)
			    continue;

            // Order of heroes/creatures must match.
            m_heroes_list.push_back( hero_ptr );
	        m_heroes_creatures_list.push_back( &creatures );

	        t_level_map_point_2d map_point = (*garrison_iter)->get_position();
            create_hero_frame( hero_ptr, map_point, hero_count );
	        hero_count++;
        }
    }
    /*
    ** Get heroes from caravans.
    */
	t_caravan_set const & caravans = m_player_ptr->get_caravans();
	t_caravan_set::const_iterator caravan_iter;
	for ( caravan_iter = caravans.begin(); caravan_iter != caravans.end(); caravan_iter++ )
	{
	    t_creature_array &    creatures = *(*caravan_iter);
        for (j = 0; j < t_creature_array::k_size; j++)
    	{
	    	hero_ptr = creatures[j].get_hero();
            if (hero_ptr == 0)
			    continue;

            // Order of heroes/creatures must match.
            m_heroes_list.push_back( hero_ptr );
	        m_heroes_creatures_list.push_back( &creatures );

	        t_level_map_point_2d map_point = t_level_map_point_2d (-1, -1, 0);
            if ((*caravan_iter)->has_arrived())
            {
                map_point = (*caravan_iter)->get_destination()->get_position();
            }
            create_hero_frame( hero_ptr, map_point, hero_count );
	        hero_count++;
        }
	}


    // Select initial hero.
    if (hero_count)
        hero_portrait_clicked( NULL, 0 );
}

// Create individual hero frame.
void t_kingdom_overview_window::create_hero_frame( t_hero * hero_ptr, t_level_map_point_2d hero_point, int index )
{
    int     i;
	t_screen_rect   portrait_rect = m_hero_list_bitmaps_ptr->find( "hero_portrait" )->get_rect();
    // Base all frames off the first frame...
    t_screen_rect   rect = m_hero_list_bitmaps_ptr->find( "hero_1" )->get_rect();
	t_window*       hero_window_ptr;
	t_text_window*  text_window_ptr;
	t_window*       window_ptr;
	t_screen_point  origin( 0, 0 );
	t_screen_point  point( 0,0 );
	t_bitmap_layer const*   layer;

    // Create hero info window.
    hero_window_ptr = new t_window ( rect, k_completely_transparent, m_hero_list_window );
    
    // Create button from portrait.
	t_button            *button_ptr;

	button_ptr = new t_button( portrait_rect.top_left(), hero_window_ptr );
    button_ptr->set_click_handler( add_2nd_argument( bound_handler( *this, &t_kingdom_overview_window::hero_portrait_clicked ), index ));
    button_ptr->set_double_click_handler( add_2nd_argument( bound_handler( *this, 
                                    &t_kingdom_overview_window::hero_portrait_double_clicked ), index ));
    button_ptr->set_right_click_text( hero_ptr->get_biography() );
    layer = hero_ptr->get_portrait();
    window_ptr = new t_bitmap_layer_window( layer, origin, button_ptr );
	button_ptr->set_released_image( window_ptr );
    button_ptr->enable( true );
    button_ptr->update_size();
	button_ptr->set_help_balloon_text( hero_ptr->get_name() );

    // Create portrait frames.
	t_toggle_button     *frame_ptr;
	layer = m_hero_list_bitmaps_ptr->find( "portrait_released" );
	rect = layer->get_rect();
	frame_ptr = new t_toggle_button( rect.top_left(), hero_window_ptr );
	window_ptr = new t_bitmap_layer_window( layer, -rect.top_left(), frame_ptr );
	frame_ptr->set_released_image( window_ptr );
    
	layer = m_hero_list_bitmaps_ptr->find( "portrait_pressed" );
	window_ptr = new t_bitmap_layer_window( layer, -rect.top_left(), frame_ptr );
	frame_ptr->set_pressed_image( window_ptr );
    frame_ptr->enable( false );

    m_portrait_button_list.push_back( frame_ptr );
 
    m_hero_windows.push_back( hero_window_ptr );
    m_hero_list_position.push_back( hero_point );

    layer = m_hero_list_bitmaps_ptr->find( "name_scroll" );
    window_ptr = new t_bitmap_layer_window( layer, origin, hero_window_ptr );

    layer = m_hero_list_bitmaps_ptr->find( "primary_skills_background" );
    window_ptr = new t_bitmap_layer_window( layer, origin, hero_window_ptr );

	rect = m_hero_list_bitmaps_ptr->find( "hero_text" )->get_rect(); // + origin;
	text_window_ptr  = new t_text_window( get_font( rect.height() ), rect, hero_window_ptr, hero_ptr->get_name(), t_pixel_24(0,0,0) );
	text_window_ptr->set_center_horizontal();

    std::vector<t_skill> skills = hero_ptr->get_primary_skills();

    /*
    ** Show primary skill icons.
    */
    int num_skills_to_display = skills.size();

    if (num_skills_to_display > k_max_skill_icons_to_display)
        num_skills_to_display = k_max_skill_icons_to_display;

    for (i=0; i< num_skills_to_display; i++)
    {
	    point = m_hero_list_bitmaps_ptr->find(format_string( "primary_%i", i+1))->get_rect().top_left();

        rect = t_screen_rect(0, 0, 52, 52);
        rect += point;

		t_skill_icon * skill_icon_ptr = new t_skill_icon( rect, hero_window_ptr );
        skill_icon_ptr->set_skill ( skills[i] );
    }

    // After skill icons.
    layer = m_hero_list_bitmaps_ptr->find( "mini_skill_frame" );
    window_ptr = new t_bitmap_layer_window( layer, origin, hero_window_ptr );
}

// Create skill frames for hero list window... From army dialog...
// *** Make separate class.
void t_kingdom_overview_window::create_skill_frames()
{
	t_screen_rect first_skill_rect;
	int			  row;
	int			  column;
	int			  columns[k_skill_frame_columns];
	int			  rows[k_skill_frame_rows];
	std::string   name;
	t_screen_point          origin(0,0);

	first_skill_rect = m_hero_list_bitmaps_ptr->find( "skill_1" )->get_rect();
	columns[0] = first_skill_rect.left;
	rows[0] = first_skill_rect.top;
	origin = first_skill_rect.top_left();
	first_skill_rect -= first_skill_rect.top_left();

	for (column = 1; column < k_skill_frame_columns; column++)
	{
		name = format_string( "skill_%i", column + 1 );
		columns[column] = m_hero_list_bitmaps_ptr->find( name )->get_rect().left;
	}

	for (row = 1; row < k_skill_frame_rows; row++)
	{
		name = format_string( "skill_row_%i", row + 1 );
		rows[row] = m_hero_list_bitmaps_ptr->find( name )->get_rect().top;
	}

	for (row = 0; row < k_skill_frame_rows; row++)
	{
		for (column = 0; column < k_skill_frame_columns; column++)
		{
			t_screen_point point( columns[column], rows[row] );

			m_frame_skills[row][column] = new t_skill_icon( t_skill(), first_skill_rect + point, m_hero_list_window );	
		}
	}
}

void t_kingdom_overview_window::show_skill_frames( t_hero const* hero_ptr )
{
	int				row_count;
	int				row;
	int				column;
	t_skill_type	skill;
	t_skill_mastery level;
	t_skill_type	primary_skill;
	int				skill_row[k_skill_primary_count];
	int				columns[k_skill_frame_rows];

    // Init.
	memset( columns, 0, sizeof(columns ));
	for (skill = t_skill_type(0); skill < k_skill_primary_count; enum_incr( skill ))
	{
		skill_row[skill] = -1;
	}

	row_count = 0;
	for (skill = t_skill_type(0); skill < k_skill_count; enum_incr( skill ))
	{
		level = hero_ptr->get_skill( skill );
		if (level == k_mastery_none)
			continue;

		primary_skill = get_primary_skill( skill );
		if (skill_row[primary_skill] == -1)
		{
			if (row_count == k_skill_frame_rows)
				continue;
			columns[row_count] = 0;
			skill_row[primary_skill] = row_count++;
		}
		row = skill_row[primary_skill];
		column = columns[row]++;
		if (column >= k_skill_frame_columns)
			continue;
		m_frame_skills[row][column]->set_skill( t_skill( skill, level ) );
		m_frame_skills[row][column]->set_visible( true );
	}

    // Set the rest to not be visible.
	for (row = 0; row < k_skill_frame_rows; row++)
	{
		for (column = columns[row]; column < k_skill_frame_columns; column++)
		{
			m_frame_skills[row][column]->set_visible( false );
		}
	}

}

void t_kingdom_overview_window::show_hero_list_screen( int starting_index )
{
    int i;
    int window_index;
	t_screen_point      point(0, 0);

    if (starting_index > m_hero_windows.size())
        return;

    if (m_heroes_list.size() == 0)
        return;
    
	m_hero_list_window->set_visible( true );

    // Show appropriate heroes.
	std::string             hero_frame_name;
    i = 0;

    // Set in-range heroes to be visible.
    for (window_index = 0; window_index<m_hero_windows.size(); window_index++)
    {
        // Set visible only those in range.
        if ((window_index >= starting_index) && (i < k_max_hero_list_windows))
        {
    		hero_frame_name = format_string ( "hero_%d", (i+1) );

    	    point = m_hero_list_bitmaps_ptr->find( hero_frame_name )->get_rect().top_left();

            m_hero_windows[ window_index ]->move ( point );
            m_hero_windows[ window_index ]->set_visible( true );

            i++;
        }
        // Set rest to be not visible.
        else
        {
            m_hero_windows[ window_index ]->set_visible( false );
        }
    }

    int scrollbar_limit = 0;
	if (m_hero_windows.size() > k_max_hero_list_windows)
    {
        scrollbar_limit = m_hero_windows.size() - k_max_hero_list_windows;

    	m_scrollbar->set_handler( bound_handler( *this, &t_kingdom_overview_window::hero_list_scrollbar_move));
        // Reset scroll bar.
    	m_scrollbar->set_limits( 0, scrollbar_limit );
    	m_scrollbar->set_visible( true );
    }
    else
    	m_scrollbar->set_visible( false );
}

void t_kingdom_overview_window::display_hero_stats( t_hero const* hero_ptr, t_creature_array * creatures )
{
	std::string text;

    // Damage text.
	bool ranged = hero_ptr->has_ability( k_ability_ranged );
	int  artifact_damage = get_artifact_damage( *hero_ptr, ranged );
	int  damage_low = hero_ptr->get_damage_low( ranged ) + artifact_damage;
	int  damage_high = hero_ptr->get_damage_high( ranged ) + artifact_damage;
	m_damage_text->set_text( format_string( "%i-%i", damage_low, damage_high ) );

    // Hit points.
	if (hero_ptr->get_wounds() > 0)
		text = format_string( "%i\n(%i)", hero_ptr->get_hit_points() - hero_ptr->get_wounds(),
		                      hero_ptr->get_hit_points() );
	else
		text = format_string( "%i", hero_ptr->get_hit_points() );
    m_health_text->set_text ( text );

    // Spell points.
    m_spell_points_text->set_text ( format_string("%i", hero_ptr->get_spell_points()) );

    // Experience.
    m_experience_text->set_text ( format_string("%i", hero_ptr->get_experience_value()) );
    std::string experience_icon_text;
    int exp_needed = hero_ptr->get_experience_needed_for_next_level();

    if (exp_needed)
        experience_icon_text = replace_keywords( get_element_help("shared", "show_experience"),
				"%amount", format_string("%d", exp_needed) );
    else
        experience_icon_text = get_element_help("shared", "show_experience_full");
    m_experience_icon->set_right_click_text( experience_icon_text );

    // Speed.
    m_speed_text->set_text ( format_string("%i", hero_ptr->get_speed()) );

    // Movement
    if (creatures)
    {
	    int maximum  = creatures->get_max_movement( *hero_ptr ) / 100;
	    int movement = creatures->get_movement( *hero_ptr ) / 100;
	    m_movement_text->set_text( format_string( "%i\n(%i)", movement, maximum ) );
    }
    else
    {
	    m_movement_text->set_text( "" );
    }


    // Luck
    int luck = hero_ptr->get_luck();
    m_luck_text->set_text ( format_string("%i", luck) );
    m_luck_icon_ptr->set_value( luck );

    // Morale
    int morale;

    if (creatures)
    {
        morale = hero_ptr->get_morale( *creatures );
    }
    else
    {
        morale = 0; //hero_ptr->get_morale();
    }
    m_morale_text->set_text ( format_string("%i", morale) );
	m_morale_icon_ptr->set_value( morale );
}

void t_kingdom_overview_window::hide_hero_list_screen()
{
	m_hero_list_window->set_visible( false );
}

void t_kingdom_overview_window::hero_list_scrollbar_move( t_scrollbar* scrollbar, int value )
{
    show_hero_list_screen( value );
}

/*--------------------------------------------------------------------------------------------------*\
**
** Town list screen.
**
\*--------------------------------------------------------------------------------------------------*/
void t_kingdom_overview_window::create_town_list_screen()
{

    int                 i;
	t_screen_rect       rect = m_background_bitmaps_ptr->find( "views" )->get_rect();
	t_screen_point      point(0, 0);

    m_town_list_bitmaps_ptr = k_kingdom_overview_town_list_bitmaps.get();

    // Window holder.
	m_town_list_window = new t_window ( rect, k_completely_transparent, this );
	m_town_list_window->set_visible( false );
    
    /*
    ** Get town list.
    */
	t_town_list*    town_list = m_player_ptr->get_towns();

    // Create all the town windows.  Then set visible as necessary.
    for (i=0; i<town_list->size(); i++)
    {
	    t_town* town_ptr = (*town_list)[i];

        create_town_frame( town_ptr );
    }
}

// Create individual town frame.
void t_kingdom_overview_window::create_town_frame( t_town * town_ptr )
{
	t_window*               window_ptr;
	t_bitmap_layer const*   layer;
	t_screen_point          origin( 0, 0 );
	t_screen_point          point( 0, 0 );

    // Base all frames off the first frame...
    t_screen_rect   rect = m_town_list_bitmaps_ptr->find( "town_1" )->get_rect();
	t_window*       town_window_ptr;

    // Create town info window.
    town_window_ptr = new t_window ( rect, k_completely_transparent, m_town_list_window );
    m_town_windows.push_back( town_window_ptr );

    /*
    ** Town thumbnail/minimap.
    */
	t_bitmap_group_ptr	    thumbnail_frame_bitmaps = g_town_list_bitmaps.get();

    // Town thumbnail image.
	t_adv_object_list_image     town_image;
	t_buffer_window *           town_image_buffer_ptr;
    t_adventure_map *           map_ptr = m_adventure_frame_ptr->get_map();
	t_screen_point              offset;

	town_image.set_town( town_ptr );

    // Create town image button.
	t_button            *button_ptr;
	offset = thumbnail_frame_bitmaps->find( "town" )->get_rect().top_left();
	button_ptr = new t_button( offset, town_window_ptr );

	town_image_buffer_ptr = new t_buffer_window( point, button_ptr );
	town_image_buffer_ptr->set_bitmap (town_image.get_bitmap());
	town_image_buffer_ptr->set_help_balloon_text( town_ptr->get_name() );
	
    button_ptr->set_released_image( town_image_buffer_ptr );
    button_ptr->set_click_handler( add_2nd_argument( bound_handler( *this, &t_kingdom_overview_window::town_image_clicked ), town_ptr ));
	button_ptr->set_double_click_handler( add_2nd_argument( bound_handler( *this, 
                                    &t_kingdom_overview_window::town_image_double_clicked ), town_ptr ));
    button_ptr->enable( true );
    button_ptr->update_size();

    // Mini-map image.
	t_micro_map_window *        map_image_ptr;
	t_level_map_point_2d        town_point = town_ptr->get_position();
	
    rect = thumbnail_frame_bitmaps->find( "map" )->get_rect();
	offset = rect.top_left();
    
    // Make mini-map a button too (to center map on town).
	button_ptr = new t_button( point + offset, town_window_ptr );
	map_image_ptr = new t_micro_map_window( t_screen_point(0,0), button_ptr );
	map_image_ptr->set_renderer( &town_image.get_map_renderer( *map_ptr, map_ptr->get_player().get_team(), rect.size(), g_town_marker.get() ) );
	map_image_ptr->set_help_balloon_text( town_ptr->get_name() );
    
    button_ptr->set_released_image( map_image_ptr );
    button_ptr->set_click_handler( add_2nd_argument( bound_handler( *this, &t_kingdom_overview_window::town_image_clicked ), town_ptr ));
    button_ptr->enable( true );
    button_ptr->update_size();

    point = m_town_list_bitmaps_ptr->find( "town_list" )->get_rect().top_left();
	layer = thumbnail_frame_bitmaps->find( "frame" );
    window_ptr = new t_bitmap_layer_window( layer, point, town_window_ptr );

    // Town gold.
    layer = m_town_list_bitmaps_ptr->find( "gold" );
    window_ptr = new t_bitmap_layer_window( layer, origin, town_window_ptr );
	window_ptr->set_help_balloon_text( k_town_gold_help_text );

    layer = m_town_list_bitmaps_ptr->find( "gold_scroll" );
    window_ptr = new t_bitmap_layer_window( layer, origin, town_window_ptr );

    /*
    ** Text.
    */
	t_text_window*          text_window_ptr;
	std::string             text_label;

    int gold_income = town_ptr->get_gold_production();
	text_label = format_string ( "%d", gold_income );
    
	rect = m_town_list_bitmaps_ptr->find( "gold_text" )->get_rect();
	text_window_ptr  = new t_text_window( get_font( 18 ), rect, town_window_ptr, text_label, t_pixel_24(0,0,0) );
	text_window_ptr->set_center_horizontal();

    // Garrison scroll.
    layer = m_town_list_bitmaps_ptr->find( "garrison_scroll" );
    window_ptr = new t_bitmap_layer_window( layer, origin, town_window_ptr );

	rect = m_town_list_bitmaps_ptr->find( "garrison_text" )->get_rect();
	text_window_ptr  = new t_text_window( get_font( rect.height()/2 ), rect, town_window_ptr, k_text_garrison_text, t_pixel_24(0,0,0) );
	text_window_ptr->set_center_horizontal();
	text_window_ptr->set_center_vertical();

    layer = m_town_list_bitmaps_ptr->find( "ring_background" );
    window_ptr = new t_bitmap_layer_window( layer, origin, town_window_ptr );

    // Show garrison.
	t_creature_array * garrison_creature_array = &town_ptr->get_garrison();

	rect = m_town_list_bitmaps_ptr->find( "garrison_rings" )->get_rect();
	window_ptr = new t_creature_array_window( rect.top_left(), &town_ptr->get_garrison(),
                                                t_creature_array_window::k_single_row, 0, town_window_ptr, false );

    // Hire creatures scroll.
    layer = m_town_list_bitmaps_ptr->find( "hire_scroll" );
    window_ptr = new t_bitmap_layer_window( layer, origin, town_window_ptr );

	rect = m_town_list_bitmaps_ptr->find( "hire_text" )->get_rect();
	text_window_ptr  = new t_text_window( get_font( rect.height()/2 ), rect, town_window_ptr, k_text_hire_text, t_pixel_24(0,0,0) );
	text_window_ptr->set_center_horizontal();
	text_window_ptr->set_center_vertical();

    std::vector<t_creature_type> creature_type_list;
	t_town_building dwelling;
	t_town_type     town_type = town_ptr->get_type();

	for (dwelling = k_town_dwelling_1; dwelling <= k_town_dwelling_8; enum_incr(dwelling))
	{
		if (!town_ptr->has( dwelling ))
			continue;

		// Show creature for this dwelling
		t_building_traits const& bld_traits = get_traits( town_type, dwelling );
        creature_type_list.push_back( bld_traits.creature );
        //town_ptr->get_population( bld_traits.creature ), window_index );
	}
    
    t_town_creature_window * creature_hire_window_ptr;
	rect = m_town_list_bitmaps_ptr->find( "hire_rings" )->get_rect();

    // Show creatures for hire.
    creature_hire_window_ptr = new t_town_creature_window( rect.top_left(), creature_type_list, town_window_ptr );

}

void t_kingdom_overview_window::show_town_list_screen( int starting_index )
{
    int i;
    int window_index;
	t_screen_point      point(0, 0);

    if (starting_index > m_town_windows.size())
        return;

	m_town_list_window->set_visible( true );

    // Show town in selected range.
	std::string             town_frame_name;
    i = 0;

    for (window_index = 0; window_index<m_town_windows.size(); window_index++)
    {
        if ((window_index >= starting_index) && (i < k_max_town_list_windows))
        {
    		town_frame_name = format_string ( "town_%d", (i+1) );

    	    point = m_town_list_bitmaps_ptr->find( town_frame_name )->get_rect().top_left();

            m_town_windows[ window_index ]->move ( point );
            m_town_windows[ window_index ]->set_visible( true );

            i++;
        }
        // Set rest to be not visible.
        else
        {
            m_town_windows[ window_index ]->set_visible( false );
        }
    }

    int scrollbar_limit = 0;
	if (m_town_windows.size() > k_max_town_list_windows)
    {
        scrollbar_limit = m_town_windows.size() - k_max_town_list_windows;

    	m_scrollbar->set_handler( bound_handler( *this, &t_kingdom_overview_window::town_list_scrollbar_move));
    	m_scrollbar->set_limits( 0, scrollbar_limit );
    	m_scrollbar->set_visible( true );
    }
    else
    	m_scrollbar->set_visible( false );
}

void t_kingdom_overview_window::town_list_scrollbar_move( t_scrollbar* scrollbar, int value )
{
    show_town_list_screen( value );
}

void t_kingdom_overview_window::hide_town_list_screen()
{
	m_town_list_window->set_visible( false );
}

/*--------------------------------------------------------------------------------------------------*\
**
** Button click handlers.
**
\*--------------------------------------------------------------------------------------------------*/
void t_kingdom_overview_window::hero_list_click( t_button *button_ptr )
{
    // button_ptr is null if called explicitedly...

    hide_army_list_screen();
    hide_town_list_screen();

    // Start with the first one (0)...
    show_hero_list_screen( 0 );
	m_scrollbar->set_position( 0 );
}

void t_kingdom_overview_window::army_list_click( t_button *button_ptr )
{
    hide_hero_list_screen();
    hide_town_list_screen();

    // Start with the first one (0)...
    show_army_list_screen( 0 );
	m_scrollbar->set_position( 0 );
}

void t_kingdom_overview_window::town_list_click( t_button *button_ptr )
{
    hide_army_list_screen();
    hide_hero_list_screen();

    show_town_list_screen( 0 );
	m_scrollbar->set_position( 0 );
}

void t_kingdom_overview_window::hero_bio_clicked( t_button *button_ptr )
{
    t_hero*     hero_ptr = m_heroes_list[ m_hero_selected ];
	
    ok_dialog( hero_ptr->get_biography(), true );
}

void t_kingdom_overview_window::hero_spellbook_clicked( t_button *button_ptr )
{
    t_hero*     hero_ptr = m_heroes_list[ m_hero_selected ];
	
	if (hero_ptr == NULL || !hero_ptr->can_cast_spells())
		return;

	t_counted_ptr<t_spellbook_window> dialog;
	t_cached_grail_data_source grail_data( 
		m_heroes_creatures_list[ m_hero_selected ]->get_grail_data() );

	dialog = new t_spellbook_window( hero_ptr, this, grail_data );
	if (!dialog->run_modal())
		return;

}

void t_kingdom_overview_window::town_image_clicked( t_button *button_ptr, t_town * town_ptr )
{
    // Center view on town.
	t_level_map_point_2d map_point = town_ptr->get_position();
    t_adventure_map *    map_ptr = m_adventure_frame_ptr->get_map();
	t_screen_point       screen_point = map_ptr->get_screen_point( map_point );

	m_adventure_frame_ptr->set_view_level( map_point.level );
	m_adventure_map_window_ptr->center_view( screen_point );
}

void t_kingdom_overview_window::town_image_double_clicked( t_button *button_ptr, t_town * town_ptr )
{
	if (town_ptr == 0)
		return;

    // Close this window.
    close();

    // Now show the town window...
	t_adventure_map_window*  map_window = m_adventure_frame_ptr->get_map_window();
	
    t_counted_ptr<t_town_window> dialog = new t_town_window( town_ptr, NULL, m_adventure_frame_ptr );

	map_window->enable_animation( false );

	dialog->run_modal();
	map_window->enable_animation( show_adventure_animations() );
    m_adventure_frame_ptr->update();

    // Trigger events for newly placed armies...
	dialog->trigger_temporary_army_events();
}

void t_kingdom_overview_window::army_leader_clicked( t_button *button_ptr, t_army* army_ptr, int index )
{
    // Center view on army.
	t_level_map_point_2d map_point = army_ptr->get_position();
    t_adventure_map *    map_ptr = m_adventure_frame_ptr->get_map();
	t_screen_point       screen_point = map_ptr->get_screen_point( map_point );

	m_adventure_frame_ptr->set_view_level( map_point.level );
	m_adventure_map_window_ptr->center_view( screen_point );

    t_screen_point  offset = m_army_list_bitmaps_ptr->find( "army_frame_highlight" )->get_rect().top_left() -
            m_army_list_bitmaps_ptr->find( "army_1" )->get_rect().top_left();
    int window_index = index - m_army_list_starting_index;

    offset += m_army_list_bitmaps_ptr->find( format_string ( "army_%d", (window_index+1) ) )->get_rect().top_left();

    // Leader highlight.
    m_army_leader_highlight->move( offset );
}

void t_kingdom_overview_window::army_leader_double_clicked( t_button *button_ptr, t_army* army_ptr )
{
    m_adventure_frame_ptr->select_army( army_ptr );
    close_click( button_ptr );
}

// button_ptr is null if called explicitedly...
void t_kingdom_overview_window::hero_portrait_clicked( t_button *button_ptr, int index )
{
    int                 i;
    t_creature_array *  creatures = m_heroes_creatures_list[ index ];
    t_hero*             hero_ptr = m_heroes_list[ index ];

	m_hero_selected = index;

    // Center view on hero.
    t_adventure_map *    map_ptr = m_adventure_frame_ptr->get_map();
    if ((m_hero_list_position[ index ].row != -1) && (m_hero_list_position[ index ].column != -1))
    {
    	t_screen_point       screen_point = map_ptr->get_screen_point( m_hero_list_position[ index ] );

    	m_adventure_frame_ptr->set_view_level( m_hero_list_position[ index ].level );
    	m_adventure_map_window_ptr->center_view( screen_point );
    }

    // Set frame graphic.
    for (i=0; i<m_portrait_button_list.size(); i++)
    {
        m_portrait_button_list[ i ]->set_pressed( false );
    }
    m_portrait_button_list[ index ]->set_pressed( true );

    /*
    ** Show stats text.
    */
    display_hero_stats( hero_ptr, creatures );
    show_skill_frames( hero_ptr );
}

void t_kingdom_overview_window::hero_portrait_double_clicked( t_button *button_ptr, int index )
{
    t_creature_array*     army_ptr = m_heroes_creatures_list[ index ];

	if (army_ptr->select())
	    close_click( button_ptr );
}

void t_kingdom_overview_window::close_click( t_button *button_ptr )
{
    m_adventure_frame_ptr->update();
    close();
}

